#!/usr/bin/env python3
# -*- coding: utf-8 -*-
"""
练习题23: 属性装饰器和描述符协议深度实践

本练习深入探讨Python的属性管理机制，包括property装饰器、
描述符协议、属性验证、计算属性等高级特性。

知识点:
- property装饰器(@property, @setter, @deleter)
- 描述符协议(__get__, __set__, __delete__, __set_name__)
- 数据描述符 vs 非数据描述符
- 属性验证和类型检查
- 计算属性和缓存属性
- 属性访问控制
- 元属性和动态属性
"""

import weakref
import functools
from typing import Any, Optional, Callable, Type, Union
from abc import ABC, abstractmethod


class ValidatedAttribute:
    """
    练习1: 实现一个通用的属性验证描述符
    
    要求:
    1. 支持类型验证
    2. 支持值范围验证
    3. 支持自定义验证函数
    4. 提供清晰的错误信息
    """
    
    def __init__(self, 
                 attr_type: Type = None,
                 min_value: Union[int, float] = None,
                 max_value: Union[int, float] = None,
                 validator: Callable[[Any], bool] = None,
                 error_msg: str = None):
        self.attr_type = attr_type
        self.min_value = min_value
        self.max_value = max_value
        self.validator = validator
        self.error_msg = error_msg
        self.name = None
    
    def __set_name__(self, owner: Type, name: str) -> None:
        """设置属性名称"""
        # TODO: 实现属性名称设置
        # 提示: 保存属性名称，用于错误信息和存储
        pass
    
    def __get__(self, instance: Any, owner: Type) -> Any:
        """获取属性值"""
        # TODO: 实现属性获取
        # 提示: 从实例的__dict__中获取值
        pass
    
    def __set__(self, instance: Any, value: Any) -> None:
        """设置属性值"""
        # TODO: 实现属性设置和验证
        # 提示: 依次进行类型验证、范围验证、自定义验证
        pass
    
    def __delete__(self, instance: Any) -> None:
        """删除属性"""
        # TODO: 实现属性删除
        pass
    
    def _validate_type(self, value: Any) -> None:
        """类型验证"""
        # TODO: 实现类型验证
        pass
    
    def _validate_range(self, value: Any) -> None:
        """范围验证"""
        # TODO: 实现范围验证
        pass
    
    def _validate_custom(self, value: Any) -> None:
        """自定义验证"""
        # TODO: 实现自定义验证
        pass


class CachedProperty:
    """
    练习2: 实现一个缓存属性描述符
    
    要求:
    1. 第一次访问时计算值
    2. 后续访问返回缓存值
    3. 支持缓存失效
    4. 支持线程安全
    """
    
    def __init__(self, func: Callable):
        self.func = func
        self.name = None
        self.__doc__ = func.__doc__
    
    def __set_name__(self, owner: Type, name: str) -> None:
        """设置属性名称"""
        # TODO: 实现属性名称设置
        pass
    
    def __get__(self, instance: Any, owner: Type) -> Any:
        """获取缓存属性值"""
        # TODO: 实现缓存属性获取
        # 提示: 检查缓存，如果没有则计算并缓存
        pass
    
    def __delete__(self, instance: Any) -> None:
        """清除缓存"""
        # TODO: 实现缓存清除
        pass


class ObservableProperty:
    """
    练习3: 实现一个可观察的属性描述符
    
    要求:
    1. 属性值变化时通知观察者
    2. 支持多个观察者
    3. 支持观察者的添加和移除
    4. 提供变化前后的值
    """
    
    def __init__(self, initial_value: Any = None):
        self.initial_value = initial_value
        self.name = None
        self._observers = weakref.WeakSet()
    
    def __set_name__(self, owner: Type, name: str) -> None:
        """设置属性名称"""
        # TODO: 实现属性名称设置
        pass
    
    def __get__(self, instance: Any, owner: Type) -> Any:
        """获取属性值"""
        # TODO: 实现属性获取
        pass
    
    def __set__(self, instance: Any, value: Any) -> None:
        """设置属性值并通知观察者"""
        # TODO: 实现属性设置和观察者通知
        # 提示: 获取旧值，设置新值，通知观察者
        pass
    
    def add_observer(self, observer: Callable) -> None:
        """添加观察者"""
        # TODO: 实现观察者添加
        pass
    
    def remove_observer(self, observer: Callable) -> None:
        """移除观察者"""
        # TODO: 实现观察者移除
        pass
    
    def _notify_observers(self, instance: Any, old_value: Any, new_value: Any) -> None:
        """通知所有观察者"""
        # TODO: 实现观察者通知
        pass


class LazyProperty:
    """
    练习4: 实现一个延迟加载属性描述符
    
    要求:
    1. 只在首次访问时初始化
    2. 支持异步初始化
    3. 支持初始化失败重试
    4. 提供初始化状态查询
    """
    
    def __init__(self, initializer: Callable, *args, **kwargs):
        self.initializer = initializer
        self.args = args
        self.kwargs = kwargs
        self.name = None
    
    def __set_name__(self, owner: Type, name: str) -> None:
        """设置属性名称"""
        # TODO: 实现属性名称设置
        pass
    
    def __get__(self, instance: Any, owner: Type) -> Any:
        """延迟初始化并获取属性值"""
        # TODO: 实现延迟初始化
        # 提示: 检查是否已初始化，如果没有则调用初始化器
        pass
    
    def __delete__(self, instance: Any) -> None:
        """重置属性状态"""
        # TODO: 实现属性重置
        pass
    
    def is_initialized(self, instance: Any) -> bool:
        """检查是否已初始化"""
        # TODO: 实现初始化状态检查
        pass


class TypedProperty:
    """
    练习5: 实现一个强类型属性描述符
    
    要求:
    1. 严格的类型检查
    2. 支持泛型类型
    3. 支持类型转换
    4. 提供类型信息
    """
    
    def __init__(self, 
                 expected_type: Type,
                 allow_none: bool = False,
                 converter: Callable = None):
        self.expected_type = expected_type
        self.allow_none = allow_none
        self.converter = converter
        self.name = None
    
    def __set_name__(self, owner: Type, name: str) -> None:
        """设置属性名称"""
        # TODO: 实现属性名称设置
        pass
    
    def __get__(self, instance: Any, owner: Type) -> Any:
        """获取属性值"""
        # TODO: 实现属性获取
        pass
    
    def __set__(self, instance: Any, value: Any) -> None:
        """设置属性值并进行类型检查"""
        # TODO: 实现类型检查和转换
        # 提示: 检查None值，进行类型转换，验证类型
        pass
    
    def _check_type(self, value: Any) -> bool:
        """检查类型"""
        # TODO: 实现类型检查
        pass
    
    def _convert_value(self, value: Any) -> Any:
        """转换值"""
        # TODO: 实现值转换
        pass


class Person:
    """
    练习6: 使用各种描述符的示例类
    
    演示不同描述符的使用方法
    """
    
    # 使用验证属性
    name = ValidatedAttribute(
        attr_type=str,
        validator=lambda x: len(x.strip()) > 0,
        error_msg="姓名不能为空"
    )
    
    age = ValidatedAttribute(
        attr_type=int,
        min_value=0,
        max_value=150,
        error_msg="年龄必须在0-150之间"
    )
    
    # 使用类型属性
    email = TypedProperty(str, allow_none=True)
    
    # 使用可观察属性
    status = ObservableProperty("active")
    
    def __init__(self, name: str, age: int, email: str = None):
        self.name = name
        self.age = age
        self.email = email
        self._salary = None
    
    @property
    def display_name(self) -> str:
        """显示名称(只读属性)"""
        # TODO: 实现显示名称
        pass
    
    @property
    def salary(self) -> Optional[float]:
        """薪资(可读写属性)"""
        # TODO: 实现薪资获取
        pass
    
    @salary.setter
    def salary(self, value: float) -> None:
        """设置薪资"""
        # TODO: 实现薪资设置和验证
        pass
    
    @salary.deleter
    def salary(self) -> None:
        """删除薪资"""
        # TODO: 实现薪资删除
        pass
    
    # 使用缓存属性
    @CachedProperty
    def expensive_calculation(self) -> float:
        """耗时计算(缓存结果)"""
        # TODO: 实现耗时计算
        # 提示: 模拟一个耗时的计算过程
        pass
    
    # 使用延迟属性
    @LazyProperty
    def database_connection(self):
        """数据库连接(延迟初始化)"""
        # TODO: 实现数据库连接初始化
        # 提示: 模拟数据库连接创建
        pass


class PropertyFactory:
    """
    练习7: 实现一个属性工厂
    
    要求:
    1. 动态创建属性
    2. 支持属性模板
    3. 支持属性继承
    4. 提供属性元信息
    """
    
    @staticmethod
    def create_validated_property(
        attr_type: Type,
        **validation_kwargs
    ) -> ValidatedAttribute:
        """创建验证属性"""
        # TODO: 实现验证属性创建
        pass
    
    @staticmethod
    def create_computed_property(
        compute_func: Callable,
        dependencies: list = None
    ) -> property:
        """创建计算属性"""
        # TODO: 实现计算属性创建
        # 提示: 当依赖属性变化时重新计算
        pass
    
    @staticmethod
    def create_readonly_property(value: Any) -> property:
        """创建只读属性"""
        # TODO: 实现只读属性创建
        pass
    
    @staticmethod
    def create_property_chain(*properties) -> property:
        """创建属性链"""
        # TODO: 实现属性链创建
        # 提示: 支持链式属性访问
        pass


class MetaPropertyClass(type):
    """
    练习8: 实现一个属性元类
    
    要求:
    1. 自动处理属性定义
    2. 支持属性继承
    3. 提供属性元信息
    4. 支持属性验证
    """
    
    def __new__(mcs, name, bases, namespace, **kwargs):
        """创建类时处理属性"""
        # TODO: 实现属性元类
        # 提示: 扫描命名空间中的属性定义，进行处理
        pass
    
    def __init__(cls, name, bases, namespace, **kwargs):
        """初始化类"""
        # TODO: 实现类初始化
        pass


def demonstrate_descriptors_properties():
    """
    演示描述符和属性的使用
    """
    print("=== 描述符和属性演示 ===")
    
    # 演示Person类的使用
    print("\n1. Person类演示:")
    try:
        # 创建Person实例
        person = Person("Alice", 30, "alice@example.com")
        
        print(f"创建的人员: {person.name}, {person.age}, {person.email}")
        print(f"显示名称: {person.display_name}")
        
        # 测试属性验证
        try:
            person.age = -5  # 应该抛出异常
        except Exception as e:
            print(f"年龄验证错误: {e}")
        
        # 测试薪资属性
        person.salary = 50000
        print(f"薪资: {person.salary}")
        
        # 测试缓存属性
        result1 = person.expensive_calculation
        result2 = person.expensive_calculation  # 应该使用缓存
        print(f"缓存计算结果: {result1}, {result2}")
        
        # 测试延迟属性
        if person.database_connection:
            print("数据库连接已建立")
        
    except Exception as e:
        print(f"Person演示出错: {e}")
    
    # 演示可观察属性
    print("\n2. 可观察属性演示:")
    try:
        def status_observer(instance, old_value, new_value):
            print(f"状态变化: {old_value} -> {new_value}")
        
        person = Person("Bob", 25)
        person.status.add_observer(status_observer)
        
        person.status = "inactive"  # 应该触发观察者
        person.status = "active"    # 应该触发观察者
        
    except Exception as e:
        print(f"可观察属性演示出错: {e}")
    
    # 演示属性工厂
    print("\n3. 属性工厂演示:")
    try:
        # 创建各种属性
        validated_prop = PropertyFactory.create_validated_property(
            str, min_length=1, max_length=100
        )
        readonly_prop = PropertyFactory.create_readonly_property("constant")
        
        print(f"属性工厂创建成功")
        
    except Exception as e:
        print(f"属性工厂演示出错: {e}")
    
    print("\n=== 描述符和属性演示完成 ===")


if __name__ == "__main__":
    demonstrate_descriptors_properties()
